package com.ti.demo.autoconfigure;

/**
 * @description: com.ti.demo.logging
 * @Author Triagen
 * @Date 2025/7/25 11:05
 */

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ti.demo.autoconfigure.log.*;
import org.apache.commons.lang3.RegExUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.zalando.logbook.*;
import org.zalando.logbook.autoconfigure.LogbookAutoConfiguration;
import org.zalando.logbook.core.CompositeSink;
import org.zalando.logbook.core.Conditions;
import org.zalando.logbook.core.ResponseFilters;

import java.io.IOException;
import java.util.UUID;
import java.util.stream.Collectors;

@ConditionalOnClass(Logbook.class)
@AutoConfiguration(before = LogbookAutoConfiguration.class)
public class LogAutoConfiguration {

    private static final String STREAM_PATTERN = "(?<=(^|\n\n))(data:)((?s).*?)(\n\n)(?=(data:|$))";

    private static final String BODY_GROUP = "$3";

    @Bean("correlationId")
    public CorrelationId correlationId() {
        return request -> String.format("00-%s-%s-01",
                UUID.randomUUID().toString().replace("-", ""),
                UUID.randomUUID().toString().replace("-", "").substring(0, 16));
    }

    @Bean("bizLogFormatter")
    public HttpLogFormatter bizLogFormatter(final ObjectMapper mapper) {
        return new BizLogFormatter(mapper);
    }

    @Bean("bizLogWriter")
    public HttpLogWriter bizLogWriter() {
        return new BizLogWriter();
    }

    @Bean("bizSink")
    public Sink bizSink(final HttpLogFormatter bizLogFormatter, final HttpLogWriter bizLogWriter) {
        return new BizSink(bizLogFormatter, bizLogWriter);
    }

    @Bean("accLogFormatter")
    public ReqRspHttpLogFormatter accLogFormatter(final ObjectMapper mapper) {
        return new AccLogFormatter(mapper);
    }

    @Bean("accLogWriter")
    public HttpLogWriter accLogWriter() {
        return new AccLogWriter();
    }

    @Bean("accSink")
    public Sink accSink(final ReqRspHttpLogFormatter accLogFormatter, final HttpLogWriter accLogWriter) {
        return new AccSink(accLogFormatter, accLogWriter);
    }

    @Bean("sink")
    public Sink sink(ObjectProvider<Sink> sinks) {
        return new CompositeSink(sinks.stream().collect(Collectors.toList()));
    }

    @ConditionalOnProperty(value = "spring.ai.log.web-flux.response", havingValue = "true")
    @Bean("responseFilter")
    public ResponseFilter responseFilter() {
        return response -> {
            if (Conditions.contentType(MediaType.TEXT_EVENT_STREAM_VALUE).test(response)) {
                try {
                    String body = response.getBodyAsString();
                    return ResponseFilters.replaceBody(r -> RegExUtils.replaceAll(body, STREAM_PATTERN, BODY_GROUP)).filter(response);
                } catch (IOException e) {
                    return response;
                }

            } else {
                return ResponseFilters.defaultValue().filter(response);
            }
        };
    }
}
